﻿using Basic.HrGatewayModular.Interface;
using Basic.HrGatewayModular.Model.Limit;
using WeDonekRpc.CacheClient.Interface;
using WeDonekRpc.Helper;

namespace Basic.HrGatewayModular.ExtendService
{
    internal class IpLimitService : IIpLimitService
    {
        private readonly ICacheController _Cache;
        private readonly IIpLimitConfig _Config;
        private const string _CacheKey = "IpLimit";
        public IpLimitService ( ICacheController cache, IIpLimitConfig config )
        {
            this._Config = config;
            this._Cache = cache;
        }

        public void CheckIsLimit ( string limitKey, string ip )
        {
            if ( this._Config.IsLimit )
            {
                string key = string.Join('_', _CacheKey, limitKey, ip);
                if ( this._Cache.TryGet(key, out IpLimitState state) && state.IsLock )
                {
                    throw new ErrorException("hr.ip.already.lock", Tools.FormatTime((int)( state.LockTime.Value - DateTime.Now ).TotalSeconds));
                }
            }
        }
        public void LimitTally ( string limitKey, string ip )
        {
            if ( this._Config.IsLimit )
            {
                string key = string.Join('_', _CacheKey, limitKey, ip);
                if ( !this._Cache.TryGet(key, out IpLimitState state) )
                {
                    state = new IpLimitState()
                    {
                        ErrorNum = 0,
                        IsLock = false
                    };
                }
                state.ErrorNum += 1;
                if ( state.ErrorNum >= this._Config.LockErrorNum )
                {
                    state.IsLock = true;
                    state.LockTime = DateTime.Now.AddSeconds(this._Config.LockTime);
                    _ = this._Cache.Set(key, state, state.LockTime.Value);
                }
                else
                {
                    _ = this._Cache.Set(key, state, DateTime.Now.AddSeconds(this._Config.StatisticWindow));
                }
            }
        }

        public bool IsLimit ( ErrorException e )
        {
            return this._Config.IsLimit && this._Config.FailCode.Contains(e.ErrorCode);
        }
    }
}
